package gredis

import (
	"bbtradeByGo/pkg/config"
	"bbtradeByGo/pkg/logging"
	"encoding/json"
	"reflect"
	"time"

	"github.com/gomodule/redigo/redis"
)

// RedisConn 初始化一个redis的连接池
var RedisConn *redis.Pool

// Setup Initialize the Redis instance
func Setup() {
	RedisConn = &redis.Pool{
		MaxIdle:     config.RedisSetting.MaxIdle,
		MaxActive:   config.RedisSetting.MaxActive,
		IdleTimeout: config.RedisSetting.IdleTimeout,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", config.RedisSetting.Host)
			if err != nil {
				return nil, err
			}
			if config.RedisSetting.Password != "" {
				if _, err := c.Do("AUTH", config.RedisSetting.Password); err != nil {
					c.Close()
					return nil, err
				}
			}
			return c, err
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}

	return
}

// Set a key/value
func Set(key string, data interface{}, time interface{}) error {
	conn := RedisConn.Get()
	defer conn.Close()
	if reflect.ValueOf(data).Kind().String() == "struct" ||
		reflect.ValueOf(data).Kind().String() == "slice" ||
		reflect.ValueOf(data).Kind().String() == "ptr" {
		data, _ = json.Marshal(data)
	}
	_, err := conn.Do("SET", key, data)
	if err != nil {
		logging.Error("pkg.gredis.Set Do error is:", err)
		return err
	}
	switch value := time.(type) {
	case int:
		_, err = conn.Do("EXPIRE", key, value)
		if err != nil {
			logging.Error("pkg.gredis.EXPIRE Do error is:", err)
			return err
		}
	}
	return nil
}

// Exists check a key
func Exists(key string) bool {
	conn := RedisConn.Get()
	defer conn.Close()

	exists, err := redis.Bool(conn.Do("EXISTS", key))
	if err != nil {
		logging.Error("pkg.gredis.Exists error is:", err)
		return false
	}

	return exists
}

// Get get a key
func Get(key string) (interface{}, error) {
	conn := RedisConn.Get()
	defer conn.Close()

	reply, err := conn.Do("GET", key)
	if err != nil {
		logging.Error("pkg.gredis.Get error is:", err)
		return nil, err
	}
	return reply, nil
}

// Delete delete a kye
func Delete(key string) (bool, error) {
	conn := RedisConn.Get()
	defer conn.Close()
	return redis.Bool(conn.Do("DEL", key))
}

// SetAdd a key/value
func SetAdd(key string, data interface{}, time interface{}) (interface{}, error) {
	conn := RedisConn.Get()
	defer conn.Close()

	if reflect.ValueOf(data).Kind().String() == "struct" ||
		reflect.ValueOf(data).Kind().String() == "slice" ||
		reflect.ValueOf(data).Kind().String() == "ptr" {
		data, _ = json.Marshal(data)
	}

	reply, err := conn.Do("SADD", key, data)
	//logging.Info("pkg.gredis.setAdd reply value is:", reply)

	if err != nil {
		logging.Error("pkg.gredis.setAdd Do error is:", err)
		return nil, err
	}
	if time != nil {
		_, err := conn.Do("EXPIRE", key, time)
		if err != nil {
			logging.Error("pkg.gredis.setAdd EXPIRE error is:", err)
			return nil, err
		}
	}
	return reply, nil
}

// LPush redis 数组的操作
func LPush(key string, data interface{}) {
	conn := RedisConn.Get()
	defer conn.Close()

	value, err := json.Marshal(data)
	if err != nil {
		logging.Error("pkg.gredis.LPush Marshal error is:", err)
		return
	}

	reply, err := conn.Do("LPUSH", key, value)
	logging.Info("pkg.gredis.LPush reply value is:", reply)
	if err != nil {
		logging.Error("pkg.gredis.LPush Do error is:", err)
		return
	}
	return
}

// HSet redis hash表的使用
func HSet(key string, field, value interface{}) {
	conn := RedisConn.Get()
	defer conn.Close()

	if reflect.ValueOf(value).Kind().String() == "struct" ||
		reflect.ValueOf(value).Kind().String() == "slice" ||
		reflect.ValueOf(value).Kind().String() == "ptr" {
		value, _ = json.Marshal(value)
	}

	reply, err := conn.Do("HSET", key, field, value)
	logging.Info("pkg.gredis.HSet reply value is:", reply)
	if err != nil {
		logging.Error("pkg.gredis.HSet Do error is:", err)
		return
	}
	return
}

// HGet redis hash表的使用
func HGet(key string, field interface{}) (interface{}, error) {
	conn := RedisConn.Get()
	defer conn.Close()
	reply, err := conn.Do("HGET", key, field)
	if err != nil {
		logging.Error("pkg.gredis.HGet Do error is:", err)
		return nil, err
	}
	return reply, nil
}

// LRange redis 数组的操作
func LRange(key string, start, end int) (interface{}, error) {
	conn := RedisConn.Get()
	defer conn.Close()
	reply, err := conn.Do("LRANGE", key, start, end)
	//logging.Info("pkg.gredis.LRange reply value is:", reply)
	if err != nil {
		logging.Error("pkg.gredis.LRANGE Do error is:", err)
		return nil, err
	}
	return reply, nil
}

// LRem redis 数组的操作
func LRem(key, value interface{}, num int) (interface{}, error) {
	conn := RedisConn.Get()
	value, err := json.Marshal(value)
	if err != nil {
		return 0, err
	}
	defer conn.Close()
	reply, err := conn.Do("LREM", key, num, value)
	//logging.Info("pkg.gredis.LREM reply value is:", reply)
	if err != nil {
		logging.Error("pkg.gredis.LREM Do error is:", err)
		return nil, err
	}
	return reply, nil
}

// LInsert redis的列表处理
func LInsert(key, op string, pivot, value interface{}) {
	conn := RedisConn.Get()
	pivot, err := json.Marshal(pivot)
	value, err = json.Marshal(value)
	if err != nil {
		return
	}
	defer conn.Close()
	reply, err := conn.Do("LINSERT", key, op, pivot, value)
	logging.Info("pkg.gredis.LINSERT reply value is:", reply)
	if err != nil {
		logging.Error("pkg.gredis.LINSERT Do error is:", err)
		return
	}
	return
}

// RPush redis的列表操作
func RPush(key, value interface{}) {
	conn := RedisConn.Get()
	value, err := json.Marshal(value)
	if err != nil {
		return
	}
	defer conn.Close()
	reply, err := conn.Do("RPush", key, value)
	logging.Info("pkg.gredis.RPush reply value is:", reply)
	if err != nil {
		logging.Error("pkg.gredis.RPush Do error is:", err)
		return
	}
	return
}
